using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Portability;
using System;

namespace BenchmarkDotNet.Disassemblers
{
    internal class SameArchitectureDisassembler
    {
        private readonly DisassemblyDiagnoserConfig config;
        private ClrMdV3Disassembler? clrMdV3Disassembler;

        internal SameArchitectureDisassembler(DisassemblyDiagnoserConfig config) => this.config = config;

        internal DisassemblyResult Disassemble(DiagnoserActionParameters parameters)
        // delay the creation to avoid exceptions at DisassemblyDiagnoser ctor
            => (clrMdV3Disassembler ??= CreateDisassemblerForCurrentArchitecture())
                    .AttachAndDisassemble(BuildDisassemblerSettings(parameters));

        private static ClrMdV3Disassembler CreateDisassemblerForCurrentArchitecture()
            => RuntimeInformation.GetCurrentPlatform() switch
            {
                Platform.X86 or Platform.X64 => new IntelDisassembler(),
                Platform.Arm64 => new Arm64Disassembler(),
                _ => throw new NotSupportedException($"{RuntimeInformation.GetCurrentPlatform()} is not supported")
            };

        private Settings BuildDisassemblerSettings(DiagnoserActionParameters parameters)
            => new (
                processId: parameters.Process.Id,
                typeName: $"BenchmarkDotNet.Autogenerated.Runnable_{parameters.BenchmarkId.Value}",
                methodName: DisassemblerConstants.DisassemblerEntryMethodName,
                printSource: config.PrintSource,
                maxDepth: config.MaxDepth,
                filters: config.Filters,
                syntax: config.Syntax.ToString(),
                tfm: parameters.BenchmarkCase.Job.Environment.GetRuntime().MsBuildMoniker,
                resultsPath: default
            );
    }
}